﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_LIMIT_TYPE_H
#define _UXS_LIMIT_TYPE_H

#pragma once

#include "Types.h"
#include "../Math/MathFunc.h"
#include "../Math/Mathematics.h"

namespace UX_STL
{
namespace UXTypes
{

	//
	// Limit Clamp Strategy
	//

	template <typename T>
	struct TLimitClampStrategy
	{
		static void Clamp (T &tValue, const T& tMin, const T& tMax)
		{
			if ( tValue > tMax )	tValue = tMax;		else
			if ( tValue < tMin )	tValue = tMin;
		}
	};


	//
	// Limit Div Strategy
	//

	template <typename T>
	struct TLimitDivStrategy
	{
		static void Clamp (T &tValue, const T& tMin, const T& tMax)
		{
			if ( tValue < tMin or tValue > tMax )
				tValue = UXMath::Mod( tValue - tMin, tMax - tMin ) + tMin;
		}
	};


	template <typename T>
	struct TLimitDivStrategy2
	{
		static void Clamp (T &tValue, const T& tMin, const T& tMax)
		{
			const T	size = tMax - tMin;

			while ( tValue < tMin )
			{
				tValue += size;
			}

			while ( tValue > tMax )
			{
				tValue -= size;
			}
		}
	};


	//
	// Limit Bitmask Strategy
	//

	template <typename T>
	struct TLimitBitmaskStrategy : TypeDescriptor::MustBeInteger<T>
	{
		static void Clamp (T &tValue, const T& tMin, const T& tMax)
		{
			ASSUME( tMin == 0 and "min value must be 0" );
			tValue &= tMax;
		}
	};


	
#	define _LIMIT_OPERATOR( _op, _ret1, _func1, _ret2, _func2, _ret3, _func3, _ret4, _func4 ) \
		template <typename B>		 _ret1 operator _op##= (const B& right)					 _func1 \
									 _ret2 operator _op  (const Self& right) const			 _func2 \
		template <typename B>		 _ret3 operator _op  (const B& right) const				 _func3 \
		template <typename B> friend _ret4 operator _op  (const B& left, const Self& right)	 _func4 \

#	define _LIMIT_OPERATOR2( _op ) \
		_LIMIT_OPERATOR( _op, \
				Self&,	{ _tValue _op##= (T)right;  _Clamp();  return *this; }, \
				Self,	{ return Self(*this) _op##= right.Value(); }, \
				Self,	{ return Self(*this) _op##= (T)right; }, \
				B,		{ return left _op (B)right.Value(); } \
		)



	//
	// Limit
	//
	
	template <typename T, T tMin, T tMax, typename S = TLimitClampStrategy<T> >
	struct TLimit
	{
	public:
		typedef TLimit< T, tMin, tMax, S >		Self;
		typedef S								Strategy;

	private:
		T	_tValue;

		void _Clamp()
		{
			Strategy::Clamp( _tValue, tMin, tMax );
		}

		STATIC_ASSERT( tMin < tMax, "incorrect values" );


	public:
		explicit
		TLimit(const T val = T(0)): _tValue(val)					{ _Clamp(); }
		TLimit(const Self &s): _tValue(s._tValue)					{}

		RVALUE_REFERENCE_ONLY(
			TLimit(Self &&s): _tValue(s._tValue)					{}
		)

		template <T _min, T _max>
		TLimit(const TLimit<T,_min,_max> &s): _tValue(s._tValue)	{ _Clamp(); }

		// get
		static T	Max()							{ return tMax; }
		static T	Min()							{ return tMin; }
		const  T	Value()	const					{ return _tValue; }
		

		// type cast
		operator const T ()	const					{ return _tValue; }


		// unary operators
		Self&	operator ++ ()						{ ++_tValue;  _Clamp();  return *this; }
		Self&	operator -- ()						{ --_tValue;  _Clamp();  return *this; }
		Self	operator ++ (int) 					{ Self ret(*this);  ++(*this);  return ret; }
		Self	operator -- (int)					{ Self ret(*this);  --(*this);  return ret; }
		Self	operator +  () const				{ return Self( +_tValue ); }
		Self	operator -  () const				{ return Self( -_tValue ); }
		bool	operator ! () const					{ return not _tValue; }
		Self	operator ~ () const					{ return Self( ~_tValue ); }


		// binary operators
		Self & operator = (const Self &right)		{ _tValue = right._tValue;  return *this; }

		_LIMIT_OPERATOR2( + );
		_LIMIT_OPERATOR2( - );
		_LIMIT_OPERATOR2( * );
		_LIMIT_OPERATOR2( / );
		_LIMIT_OPERATOR2( | );
		_LIMIT_OPERATOR2( & );
		_LIMIT_OPERATOR2( ^ );
		_LIMIT_OPERATOR2( >> );
		_LIMIT_OPERATOR2( << );

		_LIMIT_OPERATOR( %,
				Self&,	{ return _tValue = Mod( Value(), (T)right ); },
				Self,	{ return Self(*this) %= right.Value(); },
				Self,	{ return Self(*this) %= (T)right; },
				B,		{ return Mod( left, (B)right.Value() ); }
		);
	};
	

#	undef _LIMIT_OPERATOR2
#	undef _LIMIT_OPERATOR
	
#	define _LIMIT_OPERATOR( _op, _ret1, _func1, _ret2, _func2, _ret3, _func3, _ret4, _func4 ) \
		template <typename B>		 _ret1 operator _op##= (const B& right)					 _func1 \
									 _ret2 operator _op  (const Self& right) const			 _func2 \
		template <typename B>		 _ret3 operator _op  (const B& right) const				 _func3 \
		template <typename B> friend _ret4 operator _op  (const B& left, const Self& right) _func4 \

#	define _LIMIT_OPERATOR2( _op ) \
		_LIMIT_OPERATOR( _op, \
				Self&,	{ _tValue _op##= (T)right;  _Clamp();  return *this; }, \
				Self,	{ return Self(*this) _op##= right.Value(); }, \
				Self,	{ return Self(*this) _op##= (T)right; }, \
				B,		{ return left _op (B)right.Value(); } \
		)



	//
	// Dynamic Limit
	//

	template <typename T, typename S = TLimitClampStrategy<T> >
	struct TDynLimit
	{
	public:
		typedef TDynLimit< T, S >		Self;
		typedef S						Strategy;

	private:
		T		_tValue,
				_tMin,
				_tMax;

	private:
		void _Clamp()
		{
			Strategy::Clamp( _tValue, _tMin, _tMax );
		}

		void _Check() const
		{
			ASSUME( _tMin < _tMax and "incorrect values" );
		}

	public:
		TDynLimit():
			_tValue(0), _tMin(0), _tMax(1)
		{
		}

		TDynLimit(const T tVal, const T tMin, const T tMax):
			_tValue(tVal), _tMin(tMin), _tMax(tMax)
		{
			_Check();
			_Clamp();
		}

		TDynLimit(const TDynLimit<T> &s):
			_tValue(s._tValue), _tMin(s._tMin), _tMax(s._tMax)
		{
		}

		RVALUE_REFERENCE_ONLY(
			TDynLimit(TDynLimit<T> &&s):
				_tValue(s._tValue), _tMin(s._tMin), _tMax(s._tMax)
			{
			}
		)

		Self & SetLimit(const T tMin, const T tMax)
		{
			_tMin = tMin;
			_tMax = tMax;
			_Check();
			_Clamp();
			return *this;
		}


		// type cast
		operator const T ()	const					{ return _tValue; }


		// get
		const T	Value()	const						{ return _tValue; }
		const T	Min()	const						{ return _tMin; }
		const T	Max()	const						{ return _tMax; }
		

		// unary operators
		Self&	operator ++ ()						{ ++_tValue;  _Clamp();  return *this; }
		Self&	operator -- ()						{ --_tValue;  _Clamp();  return *this; }
		Self	operator ++ (int) 					{ Self ret(*this);  ++(*this);  return ret; }
		Self	operator -- (int)					{ Self ret(*this);  --(*this);  return ret; }
		Self	operator +  () const				{ return Self( +_tValue ); }
		Self	operator -  () const				{ return Self( -_tValue ); }
		bool	operator ! () const					{ return not _tValue; }
		Self	operator ~ () const					{ return Self( ~_tValue ); }

		
		// binary operators
		Self & operator = (const Self &right)		{ _tValue = right._tValue;  return *this; }

		_LIMIT_OPERATOR2( + );
		_LIMIT_OPERATOR2( - );
		_LIMIT_OPERATOR2( * );
		_LIMIT_OPERATOR2( / );
		_LIMIT_OPERATOR2( | );
		_LIMIT_OPERATOR2( & );
		_LIMIT_OPERATOR2( ^ );
		_LIMIT_OPERATOR2( >> );
		_LIMIT_OPERATOR2( << );

		_LIMIT_OPERATOR( %,
				Self&,	{ return _tValue = Mod( Value(), (T)right ); },
				Self,	{ return Self(*this) %= right.Value(); },
				Self,	{ return Self(*this) %= (T)right; },
				B,		{ return Mod( left, (B)right.Value() ); }
		);
	};


#	undef _LIMIT_OPERATOR2
#	undef _LIMIT_OPERATOR

//-------------------------------------------------------------------

}	// UXTypes
}	// UX_STL

#endif	// _UXS_LIMIT_TYPE_H